#include "httpProtocol.hpp"
#include "httpserver.hpp"
#include <memory>

void usage(const char *process)
{
    cerr << "Usage:\n\t";
    cerr << "./tcpsevver serverport" << endl;
}

// 获取正文长度
int getlen(const string &conlen)
{
    auto pos = conlen.find(": ");
    return stoi(conlen.substr(pos + 2));
}

// 获取一个完整请求
bool getOneRequest(int sock, string &reqstr)
{
    static string message; // 静态存储每一次从套接字中读取的数据
    while (true)
    {
        // 1、从sock中读取数据
        char line[1024]; // 暂存从套接字中读取的数据
        int n = recv(sock, line, sizeof(line) - 1, 0);
        if (n > 0) // 成功读取到n个字符，在第n个字符后面追加一个\0
        {
            line[n] = 0;
            message += line; // 将读取到的数据追加到message中
        }

        // 2、查看message中是否包含一个完整的请求
        // 2.1查找空行
        auto pos = message.find("\r\n\r\n");
        if (pos == string::npos) // 不存在空行
        {
            if (n <= 0) // 读取出错或连接关闭，无法继续读取
                break;

            // 继续读取
        }
        else // 存在空行，则message中存在完整的报头信息
        {
            // 查看是否存在正文
            auto first = message.find("Content-Length");
            if (first == string::npos) // 不存在正文,则空行之前的部分就是一个完整请求
            {
                reqstr = message.substr(0, pos + 4);
                message.erase(0, pos + 4);
                return true;
            }
            else // 存在正文
            {
                auto second = message.find("\r\n", first);
                int contentlen = getlen(message.substr(first, second - first));
                if (message.size() >= pos + 4 + contentlen) // 正文长度足够
                {
                    reqstr = message.substr(0, pos + 4 + contentlen);
                    message.erase(0, pos + 4 + contentlen);
                    return true;
                }
                else // 正文长度不足
                {
                    if (n <= 0) // 读取出错或连接关闭，无法继续读取
                        break;

                    // 继续读取
                }
            }
        }

        // 继续读取
    }

    return false;
}

// 从sock套接字中接收请求，发送响应
void ServerIO(int sock)
{
    request req;    // 请求
    response resp;  // 响应
    string reqstr;  // 请求字符串
    string respstr; // 响应字符串

    while (true)
    {
        // 1、从sock中读取一个完整的请求
        if (!getOneRequest(sock, reqstr)) // 获取失败
        {
            cerr << "进程" << getpid() << "获取请求失败" << endl;
            exit(GETREQ_FAIDED);
        }
        cout << "获取请求成功" << endl;

        // 2、获取请求成功,对请求进行反序列化
        cout << reqstr << endl; // 打印请求
        req.deserialize(reqstr);
        cout << "请求反序列化成功" << endl;

        // 3、根据请求生成对应的响应
        if (!getResponse(req, resp)) // 获取响应失败
            break;

        cout << "获取响应成功" << endl;

        // 4、获取响应成功，对响应进行序列化
        resp.serialize(respstr);
        cout << "响应序列化成功" << endl;

        // 5、将序列化后的响应发送给客户端
        send(sock, respstr.c_str(), respstr.size(), 0);
    }
}

//./udpserver serverport
int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        usage(argv[0]);
        exit(0);
    }

    unique_ptr<httpserver> serverptr(new httpserver(stoi(argv[1]), ServerIO));
    serverptr->start();

    return 0;
}